/**	
 * タイトル：	文件操作类
 * 説明：    	
 *			
 * 会社名：	紹興日創軟件有限公司
 * 変更履歴：	2014/08/21 NIS 何
 *			新規作成
 *
 */
package com.nissoft.framework.util;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.io.output.StringBuilderWriter;

/**
 * @author NIS 何
 * @version 1.0
 */
public abstract class FileUtil {

	public static final String DOT = ".";
	public static int EOF = -1;
	public static int DEFAULT_BUFFER_SIZE = 2048;

	public static final String LINE_SEPARATOR;

	static {
		// avoid security issues
		StringBuilderWriter buf = new StringBuilderWriter(4);
		PrintWriter out = new PrintWriter(buf);
		out.println();
		LINE_SEPARATOR = buf.toString();
		out.close();
	}

	/**
	 * 获取后缀名
	 * 
	 * @param fileName
	 *            文件名
	 */
	public static String getExtension(String fileName) {

		if (StringUtil.isEmpty(fileName) || fileName.indexOf(DOT) == -1) {
			return "";
		}
		return fileName.substring(fileName.lastIndexOf(DOT));
	}

	/**
	 * 标准化路径分隔符
	 * 
	 * @param path
	 *            原路径
	 */
	public static String standrdPath(String path) {
		return standardPath(path, false);
	}

	/**
	 * 标准化路径分隔符
	 * 
	 * @param path
	 *            原路径
	 * @param isDirectory
	 *            目录吗?
	 */
	public static String standardPath(String path, boolean isDirectory) {

		if (StringUtil.isEmpty(path)) {
			return path;
		}
		char replaceChar = File.separatorChar == '/' ? '\\' : '/';
		path = path.replace(replaceChar, File.separatorChar);
		if ((!path.endsWith(File.separator)) && isDirectory) {
			path += File.separator;
		}
		return path;
	}

	/**
	 * 以字符串读取文件
	 * 
	 * @param file
	 *            文件
	 * @throws IOException
	 */
	public static String readToString(File file) throws IOException {
		return readToString(file, Charset.defaultCharset().toString());
	}

	/**
	 * 以字符串读取文件
	 * 
	 * @param file
	 *            文件
	 * @param charsetName
	 *            字符集
	 * @throws IOException
	 */
	public static String readToString(File file, String charsetName)
			throws IOException {

		InputStreamReader in = null;
		StringBuilderWriter sw = null;
		try {
			in = new InputStreamReader(new FileInputStream(file), charsetName);
			sw = new StringBuilderWriter();
			char[] buffer = new char[DEFAULT_BUFFER_SIZE];
			int n = 0;
			while ((n = in.read(buffer)) != EOF) {
				sw.write(buffer, 0, n);
			}
			return sw.toString();
		} finally {
			closeQuietly(in);
			closeQuietly(sw);
		}
	}

	/**
	 * 以字节数组读取文件
	 * 
	 * @param file
	 *            文件
	 * @throws IOException
	 */
	public static byte[] readToByteArray(File file) throws IOException {

		InputStream in = null;
		ByteArrayOutputStream out = null;
		try {
			in = new FileInputStream(file);
			out = new ByteArrayOutputStream(DEFAULT_BUFFER_SIZE);
			byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
			int n = 0;
			while ((n = in.read(buffer)) != EOF) {
				out.write(buffer, 0, n);
			}
			return out.toByteArray();
		} finally {
			closeQuietly(in);
			closeQuietly(out);
		}
	}

	/**
	 * 以行数读取文件
	 * 
	 * @param file
	 *            文件
	 * @throws IOException
	 */
	public static List<String> readLines(File file) throws IOException {
		return readLines(file, Charset.defaultCharset().toString());
	}

	/**
	 * 以行数读取文件
	 * 
	 * @param file
	 *            文件
	 * @param charsetName
	 *            字符集
	 * @throws IOException
	 */
	public static List<String> readLines(File file, String charsetName)
			throws IOException {

		BufferedReader br = null;
		List<String> list = new ArrayList<String>();
		try {
			br = new BufferedReader(new InputStreamReader(new FileInputStream(
					file), charsetName));
			String line = br.readLine();
			while (line != null) {
				list.add(line);
				line = br.readLine();
			}
		} finally {
			closeQuietly(br);
		}
		return list;
	}

	/**
	 * 以字符串写入文件
	 * 
	 * @param file
	 *            文件
	 * @param data
	 *            字符串
	 * @throws IOException
	 */
	public static void writeString(File file, String data) throws IOException {
		writeString(file, data, Charset.defaultCharset().toString(), false);
	}

	/**
	 * 以字符串写入文件
	 * 
	 * @param file
	 *            文件
	 * @param data
	 *            字符串
	 * @param charsetName
	 *            字符集
	 * @throws IOException
	 */
	public static void writeString(File file, String data, String charsetName)
			throws IOException {
		writeString(file, data, charsetName, false);
	}

	/**
	 * 以字符串写入文件
	 * 
	 * @param file
	 *            文件
	 * @param data
	 *            字符串
	 * @param append
	 *            是否附加
	 * @throws IOException
	 */
	public static void writeString(File file, String data, boolean append)
			throws IOException {
		writeString(file, data, Charset.defaultCharset().toString(), append);
	}

	/**
	 * 以字符串写入文件
	 * 
	 * @param file
	 *            文件
	 * @param data
	 *            字符串
	 * @param charsetName
	 *            字符集
	 * @param append
	 *            是否附加
	 * @throws IOException
	 */
	public static void writeString(File file, String data, String charsetName,
			boolean append) throws IOException {

		writeByteArray(file, data.getBytes(charsetName), append);
	}

	/**
	 * 以行数写入文件
	 * 
	 * @param file
	 *            文件
	 * @param lines
	 *            行数据
	 * @throws IOException
	 */
	public static void writeLines(File file, Collection<?> lines)
			throws IOException {
		writeLines(file, lines, null, Charset.defaultCharset().toString(),
				false);
	}

	/**
	 * 以行数写入文件
	 * 
	 * @param file
	 *            文件
	 * @param lines
	 *            行数据
	 * @param lineEnd
	 *            行尾分隔符
	 * @throws IOException
	 */
	public static void writeLines(File file, Collection<?> lines, String lineEnd)
			throws IOException {
		writeLines(file, lines, lineEnd, Charset.defaultCharset().toString(),
				false);
	}

	/**
	 * 以行数写入文件
	 * 
	 * @param file
	 *            文件
	 * @param lines
	 *            行数据
	 * @param charset
	 *            字符集
	 * @throws IOException
	 */
	public static void writeLines(File file, Collection<?> lines,
			Charset charset) throws IOException {
		writeLines(file, lines, null, charset.toString(), false);
	}

	/**
	 * 以行数写入文件
	 * 
	 * @param file
	 *            文件
	 * @param lines
	 *            行数据
	 * @param append
	 *            是否附加
	 * @throws IOException
	 */
	public static void writeLines(File file, Collection<?> lines, boolean append)
			throws IOException {
		writeLines(file, lines, null, Charset.defaultCharset().toString(),
				append);
	}

	/**
	 * 以行数写入文件
	 * 
	 * @param file
	 *            文件
	 * @param lines
	 *            行数据
	 * @param lineEnd
	 *            行尾分隔符
	 * @param charset
	 *            字符集
	 * @throws IOException
	 */
	public static void writeLines(File file, Collection<?> lines,
			String lineEnd, Charset charset) throws IOException {
		writeLines(file, lines, lineEnd, charset.toString(), false);
	}

	/**
	 * 以行数写入文件
	 * 
	 * @param file
	 *            文件
	 * @param lines
	 *            行数据
	 * @param lineEnd
	 *            行尾分隔符
	 * @param append
	 *            是否附加
	 * @throws IOException
	 */
	public static void writeLines(File file, Collection<?> lines,
			String lineEnd, boolean append) throws IOException {
		writeLines(file, lines, lineEnd, Charset.defaultCharset().toString(),
				append);
	}

	/**
	 * 以行数写入文件
	 * 
	 * @param file
	 *            文件
	 * @param lines
	 *            行数据
	 * @param charset
	 *            字符集
	 * @param append
	 *            是否附加
	 * @throws IOException
	 */
	public static void writeLines(File file, Collection<?> lines,
			Charset charset, boolean append) throws IOException {
		writeLines(file, lines, null, charset.toString(), append);
	}

	/**
	 * 以行数写入文件
	 * 
	 * @param file
	 *            文件
	 * @param lines
	 *            行数据
	 * @param lineEnd
	 *            行尾分割符
	 * @param charsetName
	 *            字符集
	 * @param append
	 *            是否附加
	 * @throws IOException
	 */
	public static void writeLines(File file, Collection<?> lines,
			String lineEnd, String charsetName, boolean append)
			throws IOException {

		if (lineEnd == null) {
			lineEnd = LINE_SEPARATOR;
		}
		StringBuffer sb = new StringBuffer();
		for (Object line : lines) {
			if (line != null) {
				sb.append(line);
				sb.append(lineEnd);
			}
		}
		writeString(file, sb.toString(), charsetName, append);
	}

	/**
	 * 以字节数组写入文件
	 * 
	 * @param file
	 *            文件
	 * @param bytes
	 *            字节数组
	 * @throws IOException
	 */
	public static void writeByteArray(File file, byte[] bytes)
			throws IOException {
		writeByteArray(file, bytes, false);
	}

	/**
	 * 以字节数组写入文件
	 * 
	 * @param file
	 *            文件
	 * @param bytes
	 *            字节数组
	 * @param append
	 *            是否附加
	 * @throws IOException
	 */
	public static void writeByteArray(File file, byte[] bytes, boolean append)
			throws IOException {

		file.getParentFile().mkdirs();
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(file, append);
			fos.write(bytes);
		} finally {
			closeQuietly(fos);
		}
	}

	/**
	 * 移动文件
	 * 
	 * @param srcFile
	 *            源文件
	 * @param destFile
	 *            目标文件
	 * @throws IOException
	 */
	public static void move(File srcFile, File destFile) throws IOException {

		checkMove(srcFile, destFile);
		srcFile.renameTo(destFile);
	}

	/**
	 * 复制文件
	 * 
	 * @param srcFile
	 *            源文件
	 * @param destFile
	 *            目标文件
	 * @throws IOException
	 */
	public static void copy(File srcFile, File destFile) throws IOException {
		checkMove(srcFile, destFile);
		writeByteArray(destFile, readToByteArray(srcFile));
	}

	private static void checkMove(File srcFile, File destFile)
			throws IOException {
		if (srcFile == null) {
			throw new NullPointerException("Source must not be null");
		}
		if (destFile == null) {
			throw new NullPointerException("Destination must not be null");
		}
		if (!srcFile.exists()) {
			throw new FileNotFoundException("Source '" + srcFile
					+ "' does not exist");
		}
		if (srcFile.isDirectory()) {
			throw new IOException("Source '" + srcFile + "' is a directory");
		}
		if (destFile.isDirectory()) {
			throw new IOException("Destination '" + destFile
					+ "' is a directory");
		}
		destFile.getParentFile().mkdirs();
	}

	/**
	 * 静静的关闭
	 */
	public static void closeQuietly(Closeable closeable) {
		try {
			if (closeable != null) {
				closeable.close();
			}
		} catch (IOException e) {
		}
	}
}
